﻿using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using Jerry.DroidBuilder.Common;
using Jerry.DroidBuilder.Properties;
using Microsoft.Win32;

namespace Jerry.DroidBuilder
{
    public class DroidBuilderViewModel : NotifyPropertyChangedObject
    {
        private bool _isLocked;
        private ViewModelBase _currentModel;

        public DroidBuilderViewModel()
        {
            StatusReport.SetReportAction(UpdateStatus);

            OpenCommand = new DelegateCommand<string>(OnOpenCommand);
            SignCommand = new DelegateCommand<string>(OnSignCommand);
            RebootCommand = new DelegateCommand<string>(OnRebootCommand);
            ApplyPatchCommand = new DelegateCommand<string>(OnApplyPatchCommand);
            ChangeDirectoryCommand = new DelegateCommand<string>(OnChangeDirectoryCommand);
            UpdateReferenceCommand = new DelegateCommand<string>(OnUpdateReferenceCommand);

            Models = new ObservableCollection<ViewModelBase>();
            Patches = new ObservableCollection<string>();
            Directories = new ObservableCollection<string>();
        }

        public ICommand OpenCommand { get; private set; }
        public ICommand SignCommand { get; private set; }
        public ICommand RebootCommand { get; private set; }
        public ICommand ApplyPatchCommand { get; private set; }
        public ICommand ChangeDirectoryCommand { get; private set; }
        public ICommand UpdateReferenceCommand { get; private set; }

        public bool IsLocked
        {
            get
            {
                return _isLocked;
            }
            set
            {
                if (value != _isLocked)
                {
                    _isLocked = value;
                    OnPropertyChanged(() => IsLocked);

                    Mouse.OverrideCursor = _isLocked ? Cursors.Wait : null;
                }
            }
        }

        public string StatusInfo { get; private set; }

        public ObservableCollection<string> Patches { get; private set; }
        public ObservableCollection<string> Directories { get; private set; }

        public ObservableCollection<ViewModelBase> Models { get; private set; }

        public ViewModelBase CurrentModel
        {
            get
            {
                return _currentModel;
            }
            set
            {
                _currentModel = value;
                OnPropertyChanged(() => CurrentModel);
                OnPropertyChanged(() => IsRomView);
            }
        }

        public bool IsRomView
        {
            get
            {
                return CurrentModel is RomDirectoryViewModel;
            }
        }

        public void Initialize()
        {
            UpdateStatus(Lang.Welcome);

            var romsDirectory = Util.RomsDirectory;
            var patchDirectory = Util.PatchDirectory;

            if (Directory.Exists(romsDirectory))
            {
                foreach (var item in Directory.GetDirectories(romsDirectory))
                {
                    Directories.Add(Path.GetFileName(item));
                }
            }

            if (Directory.Exists(patchDirectory))
            {
                foreach (var item in Directory.GetFiles(patchDirectory, "*.zip"))
                {
                    Patches.Add(Path.GetFileName(item));
                }
            }
        }

        private void UpdateStatus(string status)
        {
            Application.Current.Dispatcher.Invoke((ThreadStart)delegate
            {
                StatusInfo = status;
                OnPropertyChanged(() => StatusInfo);
            });
        }

        #region Command Handlers

        private void OnCloseCommand(ViewModelBase model)
        {
            Models.Remove(model);
        }

        private void OnOpenCommand(string payload)
        {
            //var dlg = new OpenFileDialog();

            //if (dlg.ShowDialog() == true)
            //{
            //    var fileName = dlg.FileName;
            //    var model = new ThemeEditorViewModel(fileName)
            //    {
            //        Name = Path.GetFileName(fileName),
            //        CloseCommand = new DelegateCommand<ViewModelBase>(OnCloseCommand),
            //    };

            //    Models.Add(model);
            //    CurrentModel = model;
            //}
        }

        #region Sign

        private void OnSignCommand(string payload)
        {
            var dlg = new OpenFileDialog();

            if (dlg.ShowDialog() == true)
            {
                var fileName = dlg.FileName;
                var targetName =
                    Path.Combine(Path.GetDirectoryName(fileName), string.Format("{0}_signed{1}", Path.GetFileNameWithoutExtension(fileName), Path.GetExtension(fileName)));

                try
                {
                    Connector.SignApk(dlg.FileName, targetName);
                    MessageBox.Show(string.Format(Lang.Sign_Success_Message, Path.GetFileName(fileName)), Lang.Sign_Title);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format(Lang.Sign_Failure_Message, Path.GetFileName(fileName), ex.Message), Lang.Sign_Title);
                    ExceptionLogger.Log(ex);
                }
            }
        }

        #endregion

        #region Reboot

        private void OnRebootCommand(string rebootTo)
        {
            BackgroundRunner.Run(delegate
            {
                StatusReport.Update(Lang.Device_Rebooting);
                Connector.ExecuteCommand("adb", " reboot " + rebootTo);
            });
        }

        #endregion

        private void OnApplyPatchCommand(string pathName)
        {
            var model = CurrentModel as RomDirectoryViewModel;
            var patchPath = Path.Combine(Util.PatchDirectory, pathName);

            if (!File.Exists(patchPath) && (null != model))
            {
                // MessageBox...cannot apply patch.
                return;
            }

            model.ApplyPatch(patchPath);
        }

        private void OnChangeDirectoryCommand(string directory)
        {
            var romsDirectory = Util.RomsDirectory;
            var currentDirectory = Path.Combine(romsDirectory, directory);

            var model = new RomDirectoryViewModel(currentDirectory)
            {
                Name = directory,
                CloseCommand = new DelegateCommand<ViewModelBase>(OnCloseCommand),
                OpenItemCommand = new DelegateCommand<RomItem>(OnOpenItemCommand),
            };

            Models.Add(model);
            CurrentModel = model;
        }

        private void OnUpdateReferenceCommand(string payload)
        {
            UpdateReferenceViewModel model = null;

            foreach (var item in Models)
            {
                if (item is UpdateReferenceViewModel)
                {
                    model = item as UpdateReferenceViewModel;
                    break;
                }
            }

            if (null == model)
            {
                model = new UpdateReferenceViewModel
                {
                    Name = "Update Reference",
                    CloseCommand = new DelegateCommand<ViewModelBase>(OnCloseCommand)
                };

                Models.Add(model);
            }

            CurrentModel = model;
        }

        #region Open Item

        private void OnOpenItemCommand(RomItem romItem)
        {
            if (romItem.IsDirectory)
            {
                return;
            }

            TextEditorViewModel model = null;

            foreach (var item in Models)
            {
                if (item is TextEditorViewModel
                    && (item as TextEditorViewModel).FileName.Equals(romItem.FileName, StringComparison.InvariantCultureIgnoreCase))
                {
                    model = item as TextEditorViewModel;
                    break;
                }
            }

            if (null == model)
            {
                model = new TextEditorViewModel(romItem.FileName)
                {
                    Name = Path.GetFileName(romItem.FileName),
                    CloseCommand = new DelegateCommand<ViewModelBase>(OnCloseCommand)
                };

                Models.Add(model);
            }

            CurrentModel = model;
        }

        #endregion

        #endregion
    }
}
